/**
 * Represent one part of the global transaction acting on the local server. 
 * It manage an account credit or retail for one account acting for a transaction
 * 
 *  @author guillaumeR
 */

package gicom.transaction;

import gicom.generated.bankServices.Account;
import gicom.generated.bankServices.ProblemException;
import gicom.generated.transaction.State;
import gicom.generated.transaction.Vote;

import java.util.logging.Level;
import java.util.logging.Logger;

public class AccountAction {

    private Logger logger = Logger.getLogger(this.getClass().getName());

    public enum OperationType {
	DEBIT, CREDIT
    };

    private final OperationType operationType;

    private final Account account;

    //private RecoverableObject recovAcc;

    private final float bill;

    private State state;
    
    private int id;

    public AccountAction(OperationType transactionType, Account account, float bill, int id) {
	this.operationType = transactionType;
	this.account = account;
	this.bill = bill;
	this.id = id;
	this.state = State.INITIAL;
//	recovAcc = (RecoverableObject) account;
    }

    /**
     * Do the transaction
     * 
     * @param id
     *                id of the transaction
     * @return Vote.COMMIT if the account was correctly set, Vote.VOTEROLLBACK
     *         otherwise
     */
    public Vote prepare(int id) {
	try {
	    System.out.println("-------------  test d'ecriture : "+ (this.account.writeStamp() <= id));
	    if (this.account.writeStamp() <= id) {
		System.out.println("PREPARING Account ... " + this.account.number());
		// lecture
		this.account.prepare();
		this.account.readStamp(Math.max(this.account.readStamp(), id));
		this.state = State.READY;
		return Vote.VOTECOMMIT;
	    }
	} catch (gicom.generated.bankServices.ConcurrencyControlException e) {
	    logger.log(Level.SEVERE, e.getMessage());
	}

	System.out.println("Vote ROLLBACK !!!!!!!!!!!!!!!");
	return Vote.VOTEROLLBACK;
    }

    public boolean action(int id) {
	try {
	    if (this.operationType.equals(OperationType.CREDIT) && this.account.readStamp() <= id && this.account.writeStamp() <= id) {
		this.account.credit(this.bill);
		this.account.writeStamp(id);
		this.account.free();
		return true;

	    }
	    if (this.operationType.equals(OperationType.DEBIT))
		if (this.account.balance() >= this.bill && this.account.readStamp() <= id)
		    if (this.account.writeStamp() <= id) {
			this.account.debit(this.bill);
			this.account.writeStamp(id);
			this.account.free();
			return true;
		    }
	} catch (ProblemException e) {
	    e.printStackTrace();
	} catch (gicom.generated.bankServices.ConcurrencyControlException e) {
	    logger.log(Level.SEVERE, e.getMessage());
	}

	return false;
    }

    public void rollback(int id) {
	try {
	    this.account.free();
	} catch (gicom.generated.bankServices.ConcurrencyControlException e) {
	    e.printStackTrace();
	}
    }

    public State getState() {
	return state;
    }

    public void setState(State state) {
	this.state = state;
    }

    public Account getAccount() {
	return account;
    }
    
    public int getId() {
	return this.id;
    }

}
